package com.ideaaedi.shardingdynamictable.test;

import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ideaaedi.commonds.chars.CharUtil;
import com.ideaaedi.shardingdynamictable.entity.po.TransRecordPO;
import com.ideaaedi.shardingdynamictable.service.TransRecordService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@Service
public class TmpService {
    
    @Resource
    TransRecordService transRecordService;
    
    @Resource
    TmpService tmpService;
    
    /**
     * --------------- 使用注解切换数据源 ---------------
     */
    @DS("test_ds")
    public void useTestDs() {
        gogogo();
    }
    
    @DS("sharding_ds")
    public void useShardingDs() {
        gogogo();
    }
    
    /**
     * --------------- 手动切换数据源 ---------------
     */
    public void useTestDs2() {
        DynamicDataSourceContextHolder.push("test_ds");
        gogogo();
        DynamicDataSourceContextHolder.poll();
    }
    
    public void useShardingDs2() {
        DynamicDataSourceContextHolder.push("sharding_ds");
        gogogo();
        DynamicDataSourceContextHolder.poll();
    }
    
    /**
     * --------------- 使用注解切换数据源 批量操作 ---------------
     */
    @DS("test_ds")
    public void useTestDsBatch() {
        gogogoBatch();
    }
    
    @DS("sharding_ds")
    public void useShardingDsBatch() {
        gogogoBatch();
    }
    
    /**
     * --------------- 手动切换数据源 批量操作 ---------------
     */
    public void useTestDsBatch2() {
        DynamicDataSourceContextHolder.push("test_ds");
        gogogoBatch();
        DynamicDataSourceContextHolder.poll();
    }
    
    public void useShardingDsBatch2() {
        DynamicDataSourceContextHolder.push("sharding_ds");
        gogogoBatch();
        DynamicDataSourceContextHolder.poll();
    }
    
    /**
     * --------------- 同一个方法中，同时使用多个数据源 ---------------
     */
    @Transactional(rollbackFor = Exception.class) // 使用@Transactional注解的话， 多数据源切换不会生效； 都去操作默认的数据源去了
    public void useTestDsAndShardingDs1() {
        tmpService.useTestDs();
        tmpService.useShardingDs2();
    }
    
    @DSTransactional // 使用@DSTransactional注解的话， 多数据源切换正常 (使用@DS切换数据源)
    public void useTestDsAndShardingDs2() {
        tmpService.useTestDs();
        tmpService.useShardingDs2();
    }
    
    @DSTransactional // 使用@DSTransactional注解的话， 多数据源切换正常 (使用DynamicDataSourceContextHolder切换数据源)
    public void useTestDsAndShardingDs22() {
        DynamicDataSourceContextHolder.push("test_ds");
        gogogo();
        DynamicDataSourceContextHolder.poll();

        
        DynamicDataSourceContextHolder.push("sharding_ds");
        gogogo();
        DynamicDataSourceContextHolder.poll();
    }
    
    @Transactional(rollbackFor = Exception.class) // 使用@Transactional注解的话， 多数据源切换正常
    public void useTestDsAndShardingDs3() {
        tmpService.useTestDs();
        tmpService.useShardingDs2();
        System.err.println(1 / 0);
    }
    
    @DSTransactional // 使用@DSTransactional注解的话， 多数据源切换正常
    public void useTestDsAndShardingDs4() {
        tmpService.useTestDs();
        tmpService.useShardingDs2();
        System.err.println(1 / 0);
    }
    
    @DSTransactional // 使用@DSTransactional注解的话， 对mybatis-plus的批量操作 多数据源切换正常 (使用@DS切换数据源)
    public void useTestDsAndShardingDs5() {
        tmpService.useTestDsBatch();
        tmpService.useShardingDsBatch();
    }
    
    @DSTransactional // 使用@DSTransactional注解的话， 对mybatis-plus的批量操作 多数据源切换正常 (使用DynamicDataSourceContextHolder切换数据源)
    public void useTestDsAndShardingDs52() {
        tmpService.useTestDsBatch2();
        tmpService.useShardingDsBatch2();
    }
    
    @DSTransactional // 使用@DSTransactional注解的话， 对mybatis-plus的批量操作 当发生异常时, 也能正常回滚 (使用@DS切换数据源)
    public void useTestDsAndShardingDs6() {
        tmpService.useTestDsBatch();
        tmpService.useShardingDsBatch();
        System.err.println(1/0);
    }
    
    @DSTransactional // 使用@DSTransactional注解的话， 对mybatis-plus的批量操作 当发生异常时, 也能正常回滚  (使用DynamicDataSourceContextHolder切换数据源)
    public void useTestDsAndShardingDs62() {
        tmpService.useTestDsBatch2();
        tmpService.useShardingDsBatch2();
        System.err.println(1/0);
    }
    
    private void gogogoBatch() {
        ArrayList<TransRecordPO> poList = new ArrayList<>();
        
        Random random = new SecureRandom();
        for (int i = 0; i < 10; i++) {
            TransRecordPO po = new TransRecordPO();
            po.setId(IdWorker.getId());
            po.setTransDate(
                    // 随机年
                    (random.nextInt(100) + 2000)
                            + "-" +
                            // 随机月
                            StringUtils.leftPad((random.nextInt(12) + 1) + "", 2, '0')
                            + "-" +
                            // 随机日
                            (random.nextInt(30) + 1)
            );
            po.setRemark("备注" + new String(CharUtil.generateCharArr(10)));
            poList.add(po);
        }
        
        // ------------------ 成功           注：经过测试，无论是否启用mybatis-plus的rewriteBatchedStatements=true，都是成功的
        transRecordService.saveBatch(poList); // 先插入一下，以保证对应的表存在
        for (TransRecordPO po : poList) {
            po.setTransDate(null); // update语句中涉及了分片键值的更新，更新后的键值可能会导致数据所在分片位置，所以分片键的值不可更新
            po.setRemark("备注new" + new String(CharUtil.generateCharArr(10)));
        }
        transRecordService.saveOrUpdateBatch(poList);
    
        
        // ------------------（揭开注释，进行测试.） 成功           注：经过测试，无论是否启用mybatis-plus的rewriteBatchedStatements=true，都是成功的
        // transRecordService.saveBatch(poList);

        
        // ------------------（揭开注释，进行测试.） 成功           注：经过测试，无论是否启用mybatis-plus的rewriteBatchedStatements=true，都是成功的
        // poList.stream().forEach(x -> x.setTransDate(null));  // update语句中涉及了分片键值的更新，更新后的键值可能会导致数据所在分片位置，所以分片键的值不可更新
        // transRecordService.updateBatchById(poList);

        final List<TransRecordPO> list = transRecordService.list();
        for (TransRecordPO transRecord : list) {
            System.err.println(JSON.toJSONString(transRecord, true));
        }
    }
    
    public void gogogo() {
        final Random random = new SecureRandom();
        for (int i = 0; i < 10; i++) {
            TransRecordPO po = new TransRecordPO();
            po.setId(IdWorker.getId());
            po.setTransDate(
                    // 随机年
                    (random.nextInt(100) + 2000)
                            + "-" +
                            // 随机月
                            StringUtils.leftPad((random.nextInt(12) + 1) + "", 2, '0')
                            + "-" +
                            // 随机日
                            (random.nextInt(30) + 1)
            );
            po.setRemark("备注" + new String(CharUtil.generateCharArr(10)));
            transRecordService.save(po);
        }
        final List<TransRecordPO> list = transRecordService.list();
        for (TransRecordPO transRecord : list) {
            System.err.println(JSON.toJSONString(transRecord, true));
        }
    }
}
